/*
 * @brief
 * 递归锁允许同一个线程多次获取该互斥锁，可以用来解决同一线程需要多次获取同一个互斥量时死锁的问题。
 * @note
 * 虽然递归锁能解决这种情况的死锁问题，但是尽量不要使用递归锁
 * 1. 需要用到递归锁的多线程互斥处理本身就是可以简化的，允许递归很容易放纵复杂逻辑的产生
 * 2. 递归锁比起非递归锁，效率会低
 * 3.
 * 递归锁虽然允许同一个线程多次获得同一个互斥量，但可重复获得的最大次数并未具体说明，一旦超过一定的次数，再对lock进行调用就会抛出std::system错误
 */

#include <iostream>
#include <mutex>
#include <thread>

class Complex {
public:
    Complex()
        : i(1) {}
    void mul(int x) {
        std::lock_guard<std::recursive_mutex /* std::mutex */> lock(mutex);
        i *= x;
    }
    void div(int x) {
        std::lock_guard<std::recursive_mutex /* std::mutex */> lock(mutex);
        i /= x;
    }
    void both(int x, int y) {
        std::lock_guard<std::recursive_mutex /* std::mutex */> lock(mutex);
        mul(x);
        div(y);
    }
    double getResult() {
        return i;
    }

private:
    std::recursive_mutex /* std::mutex */ mutex;
    // volatile double                          i;
    /*
     * @note
     * 此处使用volatile关键字会产生警告
     * @brief
     * 1. volatile 关键字在 C++ 中表明这个变量可能在任何时候被改变，这可能是由于操作系统，硬件或者其他线程的操作。
     *    因此，编译器不能对这样的变量进行某些类型的优化。
     * 2. 当执行 i /= x 操作时，实际上是首先计算 `i / x` 的结果，然后将结果赋值给 `i`。
     *    由于 `i` 是 volatile 的，理论上它可能在这两步之间被改变。
     */
    double i;
};

int main() {
    Complex complex;
    complex.both(32, 23);
    std::cout << "Result: " << complex.getResult() << std::endl;
    return 0;
}